package com.ytktt.study.week9.task3.rpcfx.server;

import com.ytktt.study.week9.task3.rpcfx.api.RpcfxRequest;
import com.ytktt.study.week9.task3.rpcfx.api.RpcfxResolver;
import com.ytktt.study.week9.task3.rpcfx.api.RpcfxResponse;
import com.ytktt.study.week9.task3.rpcfx.exception.RpcfxException;
import com.ytktt.study.week9.task3.rpcfx.utils.StringFormatUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * Rpc调用器
 *
 * @author ytk
 */
public class RpcfxInvoker {

    private RpcfxResolver resolver;

    public RpcfxInvoker(RpcfxResolver resolver) {
        this.resolver = resolver;
    }

    public RpcfxResponse invoke(RpcfxRequest request) {
        RpcfxResponse response = new RpcfxResponse();
        String beanName = StringFormatUtils.lowerFirstLetter(request.getServiceName()) + ':' + request.getGroup() + ':' + request.getVersion();
        // 作业1：改成泛型和反射
        Object service;
        try {
            service = resolver.resolve(beanName); // this.applicationContext.getBean(serviceClass);
        } catch (RpcfxException e) {
            e.printStackTrace();
            response.setMsg(e.getErrMessage());
            response.setStatus(false);
            return response;
        }

        try {
            Method method = resolveMethodFromClass(service.getClass(), request.getMethod());
            Object result = method.invoke(service, request.getParams()); // dubbo, fastjson
            // 两次json序列化能否合并成一个
            response.setResult(result);
            response.setStatus(true);
            return response;
        } catch (IllegalAccessException | InvocationTargetException e) {

            // 3.Xstream

            // 2. 封装一个统一的RpcfxException
            // 客户端也需要判断异常
            e.printStackTrace();
            response.setMsg(e.getMessage());
            response.setStatus(false);
            return response;
        }
    }

    private Method resolveMethodFromClass(Class<?> klass, String methodName) {
        return Arrays.stream(klass.getMethods()).filter(m -> methodName.equals(m.getName())).findFirst().get();
    }


}
